package com.sos.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.time.LocalDateTime;

@Service
@RequiredArgsConstructor
@Slf4j
public class UserOnlineStatusService {

    private final RedisTemplate<String, Object> redisTemplate;
    
    // 在线状态过期时间（秒）- 30分钟
    private static final long ONLINE_STATUS_EXPIRE_SECONDS = 30 * 60;
    
    // Redis键前缀
    private static final String ONLINE_USER_PREFIX = "sos:online:user:";
    private static final String ONLINE_USER_SET = "sos:online:users";
    
    // 最小更新间隔（秒）
    private static final long MIN_UPDATE_INTERVAL = 10;
    
    // 记录上次更新时间
    private final ConcurrentHashMap<Long, LocalDateTime> lastUpdateTimes = new ConcurrentHashMap<>();

    /**
     * 设置用户在线状态
     * @param userId 用户ID
     * @param username 用户名
     */
    public void setUserOnline(Long userId, String username) {
        try {
            // 检查更新频率
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime lastUpdate = lastUpdateTimes.get(userId);
            
            if (lastUpdate != null && 
                java.time.Duration.between(lastUpdate, now).getSeconds() < MIN_UPDATE_INTERVAL) {
                log.debug("用户 {} 在线状态更新过于频繁，跳过更新", username);
                return;
            }
            
            String key = ONLINE_USER_PREFIX + userId;
            // 存储用户在线信息
            redisTemplate.opsForValue().set(key, username, ONLINE_STATUS_EXPIRE_SECONDS, TimeUnit.SECONDS);
            log.debug("已设置用户 {} 的在线状态键: {}", userId, key);
            
            // 将用户ID添加到在线用户集合中
            Long addedCount = redisTemplate.opsForSet().add(ONLINE_USER_SET, userId.toString());
            log.debug("已将用户ID {} 添加到在线用户集合 {}，添加数量: {}", userId, ONLINE_USER_SET, addedCount);
            
            // 设置集合过期时间
            Boolean expireResult = redisTemplate.expire(ONLINE_USER_SET, ONLINE_STATUS_EXPIRE_SECONDS, TimeUnit.SECONDS);
            log.debug("设置在线用户集合 {} 过期时间结果: {}", ONLINE_USER_SET, expireResult);
            
            // 记录更新时间
            lastUpdateTimes.put(userId, now);
            
            log.info("用户 {} 已设置为在线状态", username);
        } catch (Exception e) {
            log.error("设置用户 {} 在线状态失败", username, e);
        }
    }

    /**
     * 设置用户离线状态
     * @param userId 用户ID
     */
    public void setUserOffline(Long userId) {
        try {
            String key = ONLINE_USER_PREFIX + userId;
            // 删除用户的在线状态
            Boolean deleteResult = redisTemplate.delete(key);
            log.debug("删除用户 {} 在线状态键 {} 结果: {}", userId, key, deleteResult);
            
            // 从在线用户集合中移除
            Long removedCount = redisTemplate.opsForSet().remove(ONLINE_USER_SET, userId.toString());
            log.debug("从在线用户集合 {} 中移除用户ID {}，移除数量: {}", ONLINE_USER_SET, userId, removedCount);
            
            // 移除更新时间记录
            lastUpdateTimes.remove(userId);
            
            log.info("用户ID {} 已设置为离线状态", userId);
        } catch (Exception e) {
            log.error("设置用户ID {} 离线状态失败", userId, e);
        }
    }

    /**
     * 检查用户是否在线
     * @param userId 用户ID
     * @return 是否在线
     */
    public boolean isUserOnline(Long userId) {
        try {
            String key = ONLINE_USER_PREFIX + userId;
            boolean isOnline = Boolean.TRUE.equals(redisTemplate.hasKey(key));
            log.debug("检查用户 {} 是否在线: {}", userId, isOnline);
            return isOnline;
        } catch (Exception e) {
            log.error("检查用户ID {} 在线状态失败", userId, e);
            return false;
        }
    }

    /**
     * 获取所有在线用户ID集合
     * @return 在线用户ID集合
     */
    public Set<String> getOnlineUserIds() {
        try {
            Set<Object> members = redisTemplate.opsForSet().members(ONLINE_USER_SET);
            Set<String> onlineUsers = members != null ? 
                members.stream().map(Object::toString).collect(Collectors.toSet()) : 
                Collections.emptySet();
            log.info("从Redis获取在线用户集合，数量: {}", onlineUsers != null ? onlineUsers.size() : 0);
            if (onlineUsers != null) {
                log.debug("在线用户ID列表: {}", onlineUsers);
            }
            return onlineUsers;
        } catch (Exception e) {
            log.error("获取在线用户集合失败", e);
            return null;
        }
    }
    
    /**
     * 同步数据库和Redis中的在线状态
     * @param userId 用户ID
     */
    public void syncOnlineStatus(Long userId) {
        try {
            log.debug("开始同步用户 {} 的在线状态", userId);
            
            // 从数据库获取用户在线状态
            String key = ONLINE_USER_PREFIX + userId;
            Boolean existsInRedis = redisTemplate.hasKey(key);
            
            if (Boolean.TRUE.equals(existsInRedis)) {
                // 如果Redis中有数据，确保它没有过期
                redisTemplate.expire(key, ONLINE_STATUS_EXPIRE_SECONDS, TimeUnit.SECONDS);
                redisTemplate.expire(ONLINE_USER_SET, ONLINE_STATUS_EXPIRE_SECONDS, TimeUnit.SECONDS);
                log.debug("已刷新用户 {} 和集合的过期时间", userId);
            }
        } catch (Exception e) {
            log.error("同步用户 {} 在线状态失败", userId, e);
        }
    }

    /**
     * 更新用户在线状态（延长过期时间）
     * @param userId 用户ID
     */
    public void refreshUserOnlineStatus(Long userId) {
        try {
            // 检查更新频率
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime lastUpdate = lastUpdateTimes.get(userId);
            
            if (lastUpdate != null && 
                java.time.Duration.between(lastUpdate, now).getSeconds() < MIN_UPDATE_INTERVAL) {
                log.debug("用户ID {} 在线状态刷新过于频繁，跳过刷新", userId);
                return;
            }
            
            String key = ONLINE_USER_PREFIX + userId;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {
                redisTemplate.expire(key, ONLINE_STATUS_EXPIRE_SECONDS, TimeUnit.SECONDS);
                redisTemplate.expire(ONLINE_USER_SET, ONLINE_STATUS_EXPIRE_SECONDS, TimeUnit.SECONDS);
                
                // 记录更新时间
                lastUpdateTimes.put(userId, now);
                log.debug("已刷新用户 {} 和集合 {} 的过期时间", key, ONLINE_USER_SET);
            } else {
                log.warn("尝试刷新不存在的用户 {} 的在线状态", userId);
            }
        } catch (Exception e) {
            log.error("刷新用户ID {} 在线状态失败", userId, e);
        }
    }
}